home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / vbdatabs / ustring.cpp < prev    next >
C/C++ Source or Header  |  1999-03-31  |  17KB  |  608 lines

  1. // ------------------------------- //
  2. // -------- Start of File -------- //
  3. // ------------------------------- //
  4. // ----------------------------------------------------------- // 
  5. // C++ Source Code File Name: ustring.cpp 
  6. // Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
  7. // Produced By: Doug Gaer 
  8. // File Creation Date: 11/29/1996  
  9. // Date Last Modified: 03/31/1999
  10. // Copyright (c) 1997 Douglas M. Gaer
  11. // ----------------------------------------------------------- // 
  12. // ------------- Program Description and Details ------------- // 
  13. // ----------------------------------------------------------- // 
  14. /*
  15. The VBD C++ classes are copyright (c) 1997, by Douglas M. Gaer.
  16. All those who put this code or its derivatives in a commercial
  17. product MUST mention this copyright in their documentation for
  18. users of the products in which this code or its derivative
  19. classes are used. Otherwise, you have the freedom to redistribute
  20. verbatim copies of this source code, adapt it to your specific
  21. needs, or improve the code and release your improvements to the
  22. public provided that the modified files carry prominent notices
  23. stating that you changed the files and the date of any change.
  24.  
  25. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
  26. THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
  27. IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
  28. YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
  29. CORRECTION.
  30.  
  31. The UString class is a user-defined string class used to create
  32. and manipulate non null-terminated resizable, variable-length
  33. strings of binary data. UString objects are implemented as a
  34. concrete data type, just like the built-in data types: char,
  35. int, long, float, and double. The UString class supports string
  36. concatenation, find, fill, and sub-string creation.
  37. */
  38. // ----------------------------------------------------------- // 
  39. #include <ctype.h>
  40. #include "ustring.h"
  41.  
  42. StrData StrData::Null_Ptr;
  43.  
  44. void *StrData::operator new(size_t StrSize, unsigned Bytes)
  45. // Overloaded new operator used to allocate memory for the size
  46. // of a StrData object plus number of bytes that represent the 
  47. // length of the string's data. The memory for the string is
  48. // allocated as an array of characters. It is the responsibility
  49. // of the UString class to keep track of the string's length.
  50. // The UString class must store the string data immediately following
  51. // the reference count. A null pointer object will be statically 
  52. // allocated when a new StrData object is constructed. Null strings
  53. // will always point to the null pointer object.
  54. {
  55.   // StrSize already accounts for one character
  56.   void *ptr = new char[StrSize + Bytes - 1];
  57.   if(!ptr) { // If allocation fails reference Null_Ptr
  58.     ptr = &Null_Ptr;
  59.     ((StrData *)ptr)->RefCount++;
  60.   }
  61.   return ptr;
  62. }
  63.  
  64. void StrData::operator delete(void *ptr)
  65. // The delete operator is overloaded so that
  66. // both the string data the reference count
  67. // are deleted.
  68. {
  69.   delete[] (char *)ptr;
  70. }
  71.  
  72. int UString::Alloc(unsigned Bytes, int GB)
  73. {
  74.   DataPtr = new(Bytes) StrData;
  75.   TextPtr = DataPtr->Data;
  76.   Len = 0;
  77.   if (IsNull()) { // Could not allocate memory for string
  78.     DimLen = 1;
  79.     GrowBy = 0;
  80.     return 0;
  81.   }
  82.   else {
  83.     DimLen = Bytes;
  84.     GrowBy = GB;
  85.     return 1;
  86.   }
  87. }
  88.       
  89. void UString::Bind(const UString &s)
  90. {
  91.   // Bind DataPtr to the same that s is bound to
  92.   DataPtr = s.DataPtr;
  93.   DataPtr->RefCount++;
  94. }
  95.  
  96. void UString::UnBind()
  97. {
  98.   DataPtr->RefCount--;
  99.  
  100.   // Make sure RefCount is a non-zero value
  101.   if(DataPtr == &StrData::Null_Ptr && DataPtr->RefCount == 0)
  102.     DataPtr->RefCount = 1;
  103.  
  104.   if(DataPtr->RefCount == 0) delete DataPtr;
  105. }
  106.  
  107. void UString::NewBinding(const UString &s)
  108. {
  109.   // Unbind string from DataPtr that holds it, and
  110.   // bind it to the DataPtr shared by s
  111.   if(DataPtr != s.DataPtr) {
  112.     UnBind();
  113.     Bind(s);
  114.   }
  115. }
  116.  
  117. UString::UString(const char *s, unsigned Bytes, int GB)
  118. {
  119.   if(Alloc(Bytes, GB)) CopyN(s, Bytes);
  120. }
  121.  
  122. UString::UString(const char *s, int GB)
  123. {
  124.   unsigned StringLen = strlen(s);
  125.   unsigned DimensionLen = StringLen;
  126.   if(GB) { // Compute next highest multiple of GB
  127.     unsigned AddValue = (DimensionLen % GB) ? GB : 0;
  128.     DimensionLen = (DimensionLen / GB) * GB + AddValue;
  129.   }
  130.   if(Alloc(DimensionLen, GB)) CopyN(s, StringLen);
  131. }
  132.  
  133. UString::UString(const UString &s, unsigned Offset, unsigned Bytes, int GB)
  134. // A constructor used to create a subset of this string.
  135. {
  136.   Bind(s);
  137.  
  138.   // Keep offset and length in range
  139.   if(Offset > s.Len-1) Offset = s.Len - 1;
  140.   if(Bytes + Offset > s.Len) Bytes = s.Len - Offset;
  141.  
  142.   // Set max and logical bounds of the substring
  143.   DimLen = Bytes;
  144.   Len = Bytes;
  145.   GrowBy = GB;
  146.   TextPtr = s.TextPtr + Offset; // Compute starting text element
  147. }
  148.  
  149. UString::UString(const UString &s)
  150. {
  151.   Bind(s);
  152.   Len = s.Len;
  153.   DimLen = s.DimLen;
  154.   GrowBy = s.GrowBy;
  155.   TextPtr = s.TextPtr;
  156. }
  157.  
  158. UString::~UString()
  159. {
  160.   UnBind();
  161. }
  162.  
  163. UString &UString::operator=(const UString &s)
  164. {
  165.   if(this != &s) {
  166.     NewBinding(s);
  167.     Len = s.Len;
  168.     DimLen = s.DimLen;
  169.     GrowBy = s.GrowBy;
  170.     TextPtr = s.TextPtr;
  171.   }
  172.   return *this;
  173. }
  174.  
  175. unsigned UString::InsReplAt(unsigned Pos,
  176.                const char *s, unsigned Bytes, int Ins)
  177. {
  178.   unsigned Room, Needed, AddVal;
  179.   
  180.   if(Ins) {
  181.     Room = DimLen - Len;
  182.     if(Bytes > Room && GrowBy != 0) {
  183.       Needed = (Bytes - Room);
  184.       AddVal = (Needed % GrowBy) ? GrowBy : 0;
  185.       Needed = (Needed / GrowBy) * GrowBy + AddVal;
  186.       Grow_By(Needed);
  187.     }
  188.   }
  189.  
  190.   if (!EnsureUnique()) return 0; // Can't update
  191.   if (Pos >= Len) Pos = Len; // Don't allow gaps
  192.  
  193.   if(Ins) { // Keep things in range. May have to truncate
  194.     if(Bytes > DimLen - Len) Bytes = DimLen - Len;
  195.     if(Pos < Len) {
  196.       // Make room in the middle for inserted data
  197.       memmove(TextPtr+Pos+Bytes, TextPtr+Pos, Len-Pos);
  198.     }
  199.   }
  200.   else {
  201.     if(Bytes > DimLen - Pos) Bytes = DimLen -Pos;
  202.   }
  203.  
  204.   // Copy in source, compute final length
  205.   memmove(TextPtr+Pos, s, Bytes);
  206.   if(Ins) {
  207.     Len += Bytes;
  208.   }
  209.   else {
  210.     if((Pos+Bytes) > Len) Len = Pos+Bytes;
  211.   }
  212.   return Bytes;
  213. }
  214.  
  215. int UString::Realloc(unsigned NewDimLen, int Keep)
  216. {
  217.   if(GrowBy == 0) return 0;
  218.  
  219.   StrData *NewStrData = new(NewDimLen) StrData;
  220.   if(NewStrData == &StrData::Null_Ptr) return 0;
  221.  
  222.   if(Keep) { // Copy old data into new space.
  223.     if(NewDimLen < Len) Len = NewDimLen;
  224.     memmove(NewStrData->Data, TextPtr, Len);
  225.   }
  226.   else { // Do not keep old data
  227.     Len = 0;
  228.   }
  229.  
  230.   UnBind();                // Unbind from old data
  231.   DataPtr = NewStrData;    // Bind to new Data
  232.   TextPtr = DataPtr->Data; // Point to starting text
  233.   DimLen = NewDimLen;      // Record new allocated length
  234.   return 1;
  235. }
  236.  
  237. int UString::EnsureUnique()
  238. {
  239.   if(!IsUnique()) {
  240.     // Create a unique clone of this string
  241.     UString buf(DimLen, GrowBy);
  242.     buf.CopyN(TextPtr, Len);
  243.     if(buf.IsNull()) return 0; // Could not copy
  244.     NewBinding(buf);           // Bind to copy
  245.     TextPtr = buf.TextPtr;     // Initialize starting text element
  246.   }
  247.   return 1;
  248. }
  249.  
  250. void UString::SetLength(unsigned Bytes)
  251. {
  252.   if(Bytes > DimLen) Bytes = DimLen;
  253.   Len = Bytes;
  254. }
  255.  
  256. void UString::CopyN(const char *s, unsigned Bytes)
  257. {
  258.   Len = 0; InsReplAt(0, s, Bytes);
  259. }
  260.  
  261. void UString::Copy(const char *s)
  262. {
  263.   CopyN(s, strlen(s));
  264. }
  265.  
  266. void UString::Copy(const UString &s)
  267. {
  268.   CopyN(s.TextPtr, s.Len);
  269. }
  270.  
  271. unsigned UString::Find(char *s, unsigned Offset)
  272. // Returns index of first occurrence of pattern char *s   
  273. // Returns 0xffff if pattern not found
  274. {
  275.   char *Start = TextPtr + Offset; // Start of string data
  276.   char *Next = Start;             // Next string element
  277.   char *Pattern = s;              // Next pattern element
  278.   unsigned i = Offset;            // Next string element index
  279.   
  280.   while(i < Len && *Pattern) {
  281.     if (*Next == *Pattern) {
  282.       Pattern++;
  283.       if(*Pattern == 0) return i; // Pattern was found
  284.       Next++;
  285.     }
  286.     else {
  287.       i++;
  288.       Start++;
  289.       Next